#include "fileappender.h"
#include <QDir>
#include <QTimer>

FileAppender::FileAppender(LogLevel level, const QString &logPath)      // 默认保留10个文件
    : BaseAppender(level),
    m_logPath(logPath)
{
    // 确保日志目录存在（不存在则创建）
    createLogDir();
    // 初始化第一个日志文件
    createNewLogFile();
}

FileAppender::~FileAppender()
{
    QMutexLocker locker(&m_mutex);  // 线程安全保护
    flushCache();                   // 销毁前强制刷缓存
    closeCurrentFile();             // 关闭当前文件
    delete m_logFile;
    delete m_textStream;
}

void FileAppender::setLogPathAndBaseName(const QString &path, const QString &baseName)
{
    QMutexLocker locker(&m_mutex);
    m_logPath = path;
    m_baseName = baseName;
    createLogDir();          // 确保新路径存在
    splitLogFile();          // 分割当前文件，切换到新路径
}

void FileAppender::setMaxFileCount(int count)
{
    QMutexLocker locker(&m_mutex);
    m_maxFileCount = count;
    cleanOldFiles();         // 立即执行旧文件清理
}

void FileAppender::append(LogLevel level, const QString &msg)
{
    QMutexLocker locker(&m_mutex);  // 线程安全：避免多线程写冲突

    // 1. 等级过滤：低于当前等级不处理
    if (level < m_level) return;

    // 2. 检查文件状态：未打开则重建
    if (!m_logFile || !m_logFile->isOpen())
    {
        createNewLogFile();
        if (!m_logFile->isOpen()) return;  // 重建失败则退出
    }

    // 3. 日志加入缓存（末尾补换行符，保证每条日志一行）
    QString logMsg = msg + "\n";
    m_cache.append(logMsg.toUtf8());

    // 4. 检查是否需要强制刷新（等级触发/缓存满触发）
    bool needFlush = (level >= m_forceFlushLevel) || (m_cache.size() >= m_cacheSize);
    if (needFlush)
    {
        flushCache();  // 刷缓存到文件
        // 刷新后检查是否需要分割文件
        if (checkNeedSplit())
        {
            splitLogFile();  // 执行文件分割
        }
    }
}

void FileAppender::createLogDir()
{
    QDir dir(m_logPath);
    if (!dir.exists())
    {
        dir.mkpath(".");  // 递归创建所有层级目录
    }
}

void FileAppender::createNewLogFile()
{
    closeCurrentFile();  // 先关闭旧文件

    // 新文件路径：路径/基础名.log（如 logs/app.log）
    QString newFilePath = QString("%1/%2.log").arg(m_logPath,m_baseName);
    m_logFile = new QFile(newFilePath);

    // 打开文件（追加模式+文本模式）
    if (m_logFile->open(QIODevice::Append | QIODevice::Text))
    {
        m_textStream = new QTextStream(m_logFile);

        // 兼容Qt5和Qt6的编码设置（核心修正）
#if QT_VERSION_MAJOR >= 6
        // Qt6：使用setEncoding，参数为QStringConverter::Utf8
        m_textStream->setEncoding(QStringConverter::Utf8);
#else
        // Qt5：使用setCodec，参数为编码字符串
        m_textStream->setCodec("UTF-8");
#endif

        // 初始化当前文件的行数和大小（基于已有内容）
        m_currentFileSize = m_logFile->size();
        m_currentLines = countFileLines(newFilePath);

        // 记录当前文件创建时间（用于时间分割判断）
        QFileInfo fileInfo(newFilePath);
        m_fileCreateTime = fileInfo.birthTime();
    }
    else
    {
        // 打开失败：释放资源（避免内存泄漏）
        delete m_logFile;
        m_logFile = nullptr;
        delete m_textStream;
        m_textStream = nullptr;
    }
}

void FileAppender::closeCurrentFile()
{
    if (m_logFile && m_logFile->isOpen())
    {
        m_logFile->close();
    }
}

bool FileAppender::checkNeedSplit()
{
    switch (m_splitMode)
    {
    case SplitMode::Size:
        // 按大小：当前文件大小 >= 分割阈值
        return m_currentFileSize >= m_splitSize;
    case SplitMode::Line:
        // 按行数：当前文件行数 >= 分割阈值
        return m_currentLines >= m_splitLines;
    case SplitMode::Time:
        // 按时间：当前时间超过分割单位（如跨天、跨小时）
        return isTimeOverThreshold();
    default:
        return false;
    }
}

bool FileAppender::isTimeOverThreshold()
{
    QDateTime now = QDateTime::currentDateTime();
    switch (m_timeUnit)
    {
    case TimeUnit::Hour:
        return now > m_fileCreateTime.addSecs(3600);  // 1小时=3600秒
    case TimeUnit::Day:
        return now > m_fileCreateTime.addDays(1);     // 1天
    case TimeUnit::Week:
        return now > m_fileCreateTime.addDays(7);     // 1周
    case TimeUnit::Month:
        return now > m_fileCreateTime.addMonths(1);   // 1个月
    default:
        return false;
    }
}

void FileAppender::splitLogFile()
{
    if (!m_logFile || !m_logFile->isOpen()) return;

    // 1. 关闭当前文件
    closeCurrentFile();

    // 2. 重命名当前文件为备份文件（格式：基础名_时间戳.log）
    QString oldFilePath = m_logFile->fileName();
    QString timeStamp = QDateTime::currentDateTime().toString("yyyyMMddHHmmss");
    QString backupFilePath = QString("%1/%2_%3.log").arg(m_logPath,m_baseName,timeStamp);
    QFile::rename(oldFilePath, backupFilePath);

    // 3. 清理超过最大数量的旧文件
    cleanOldFiles();

    // 4. 创建新的当前文件
    createNewLogFile();
}

void FileAppender::cleanOldFiles()
{
    QDir dir(m_logPath);
    // 筛选符合格式的日志文件：基础名_*.log（备份文件）+ 基础名.log（当前文件）
    QString filter = QString("%1*.log").arg(m_baseName);
    QFileInfoList fileList = dir.entryInfoList({ filter }, QDir::Files, QDir::Time | QDir::Reversed);

    // 超过最大文件数：删除最早的文件
    while (fileList.size() > m_maxFileCount)
    {
        QFileInfo oldFile = fileList.takeLast();  // 最后一个是最早的
        QFile::remove(oldFile.filePath());
    }
}

void FileAppender::flushCache()
{
    if (m_cache.isEmpty() || !m_textStream || !m_logFile->isOpen()) return;

    // 1. 写入缓存内容到文件
    *m_textStream << m_cache;
    m_textStream->flush();  // 强制刷盘

    // 2. 更新当前文件大小（缓存字节数）
    m_currentFileSize += m_cache.size();

    // 3. 更新当前文件行数（统计缓存中的换行符）
    m_currentLines += m_cache.count('\n');

    // 4. 清空缓存
    m_cache.clear();
}

int FileAppender::countFileLines(const QString &filePath)
{
    QFile file(filePath);
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) return 0;

    int lineCount = 0;
    QTextStream stream(&file);
    while (!stream.atEnd())
    {
        stream.readLine();
        lineCount++;
    }
    file.close();
    return lineCount;
}
